#include <math.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>

#if 0
extern char * _argv_0;
#define MATH do { if (getenv("LIBM_DEBUG")) { fprintf(stderr, "%s called math function %s\n", _argv_0, __func__); } } while (0)
#else
#define MATH (void)0
#endif

double exp(double x) {
	return pow(2.71828182846, x);
}

int abs(int j) {
	return (j < 0 ? -j : j);
}

double fabs(double x) {
	MATH;
	return __builtin_fabs(x);
}

float fabsf(float x) {
	return fabs(x);
}

float sqrtf(float x) {
	return sqrt(x);
}

static double bad_sine_table[] = {
	0,
		0.01745240644,
		0.03489949671,
		0.05233595625,
		0.06975647375,
		0.08715574276,
		0.1045284633,
		0.1218693434,
		0.139173101,
		0.1564344651,
		0.1736481777,
		0.1908089954,
		0.2079116908,
		0.2249510544,
		0.2419218956,
		0.2588190451,
		0.2756373559,
		0.2923717048,
		0.3090169944,
		0.3255681545,
		0.3420201434,
		0.3583679496,
		0.3746065935,
		0.3907311285,
		0.4067366431,
		0.4226182618,
		0.4383711468,
		0.4539904998,
		0.4694715628,
		0.4848096203,
		0.5000000001,
		0.515038075,
		0.5299192643,
		0.5446390351,
		0.5591929035,
		0.5735764364,
		0.5877852524,
		0.6018150232,
		0.6156614754,
		0.6293203911,
		0.6427876098,
		0.6560590291,
		0.6691306064,
		0.6819983601,
		0.6946583705,
		0.7071067813,
		0.7193398004,
		0.7313537017,
		0.7431448256,
		0.7547095803,
		0.7660444432,
		0.7771459615,
		0.7880107537,
		0.7986355101,
		0.8090169944,
		0.8191520444,
		0.8290375726,
		0.838670568,
		0.8480480962,
		0.8571673008,
		0.8660254039,
		0.8746197072,
		0.8829475929,
		0.8910065243,
		0.8987940464,
		0.9063077871,
		0.9135454577,
		0.9205048535,
		0.9271838546,
		0.9335804266,
		0.9396926208,
		0.9455185757,
		0.9510565163,
		0.956304756,
		0.961261696,
		0.9659258263,
		0.9702957263,
		0.9743700648,
		0.9781476008,
		0.9816271835,
		0.984807753,
		0.9876883406,
		0.9902680688,
		0.9925461517,
		0.9945218954,
		0.9961946981,
		0.9975640503,
		0.9986295348,
		0.999390827,
		0.9998476952,
		1,
		0.9998476952,
		0.999390827,
		0.9986295347,
		0.9975640502,
		0.9961946981,
		0.9945218953,
		0.9925461516,
		0.9902680687,
		0.9876883406,
		0.984807753,
		0.9816271834,
		0.9781476007,
		0.9743700647,
		0.9702957262,
		0.9659258262,
		0.9612616959,
		0.9563047559,
		0.9510565162,
		0.9455185755,
		0.9396926207,
		0.9335804264,
		0.9271838545,
		0.9205048534,
		0.9135454575,
		0.9063077869,
		0.8987940462,
		0.8910065241,
		0.8829475927,
		0.874619707,
		0.8660254036,
		0.8571673006,
		0.848048096,
		0.8386705678,
		0.8290375724,
		0.8191520441,
		0.8090169942,
		0.7986355099,
		0.7880107534,
		0.7771459613,
		0.7660444429,
		0.75470958,
		0.7431448253,
		0.7313537014,
		0.7193398001,
		0.707106781,
		0.6946583702,
		0.6819983598,
		0.6691306061,
		0.6560590288,
		0.6427876094,
		0.6293203908,
		0.6156614751,
		0.6018150229,
		0.587785252,
		0.5735764361,
		0.5591929032,
		0.5446390347,
		0.5299192639,
		0.5150380746,
		0.4999999997,
		0.4848096199,
		0.4694715625,
		0.4539904994,
		0.4383711465,
		0.4226182614,
		0.4067366428,
		0.3907311282,
		0.3746065931,
		0.3583679492,
		0.342020143,
		0.3255681541,
		0.309016994,
		0.2923717044,
		0.2756373555,
		0.2588190447,
		0.2419218952,
		0.224951054,
		0.2079116904,
		0.190808995,
		0.1736481773,
		0.1564344647,
		0.1391731006,
		0.121869343,
		0.1045284629,
		0.08715574235,
		0.06975647334,
		0.05233595584,
		0.0348994963,
		0.01745240603,
		-0.000000000410206857,
		-0.01745240685,
		-0.03489949712,
		-0.05233595666,
		-0.06975647416,
		-0.08715574317,
		-0.1045284637,
		-0.1218693438,
		-0.1391731014,
		-0.1564344655,
		-0.1736481781,
		-0.1908089958,
		-0.2079116912,
		-0.2249510548,
		-0.241921896,
		-0.2588190455,
		-0.2756373562,
		-0.2923717052,
		-0.3090169948,
		-0.3255681549,
		-0.3420201438,
		-0.35836795,
		-0.3746065938,
		-0.3907311289,
		-0.4067366435,
		-0.4226182622,
		-0.4383711472,
		-0.4539905002,
		-0.4694715632,
		-0.4848096207,
		-0.5000000004,
		-0.5150380753,
		-0.5299192646,
		-0.5446390354,
		-0.5591929039,
		-0.5735764368,
		-0.5877852527,
		-0.6018150235,
		-0.6156614757,
		-0.6293203914,
		-0.6427876101,
		-0.6560590294,
		-0.6691306067,
		-0.6819983604,
		-0.6946583708,
		-0.7071067815,
		-0.7193398007,
		-0.731353702,
		-0.7431448258,
		-0.7547095806,
		-0.7660444435,
		-0.7771459618,
		-0.7880107539,
		-0.7986355104,
		-0.8090169947,
		-0.8191520446,
		-0.8290375729,
		-0.8386705682,
		-0.8480480964,
		-0.857167301,
		-0.8660254041,
		-0.8746197074,
		-0.8829475931,
		-0.8910065244,
		-0.8987940465,
		-0.9063077873,
		-0.9135454579,
		-0.9205048537,
		-0.9271838548,
		-0.9335804267,
		-0.939692621,
		-0.9455185758,
		-0.9510565165,
		-0.9563047561,
		-0.9612616961,
		-0.9659258264,
		-0.9702957264,
		-0.9743700649,
		-0.9781476009,
		-0.9816271836,
		-0.9848077531,
		-0.9876883407,
		-0.9902680688,
		-0.9925461517,
		-0.9945218954,
		-0.9961946981,
		-0.9975640503,
		-0.9986295348,
		-0.999390827,
		-0.9998476952,
		-1,
		-0.9998476951,
		-0.999390827,
		-0.9986295347,
		-0.9975640502,
		-0.996194698,
		-0.9945218953,
		-0.9925461516,
		-0.9902680687,
		-0.9876883405,
		-0.9848077529,
		-0.9816271833,
		-0.9781476006,
		-0.9743700646,
		-0.9702957261,
		-0.9659258261,
		-0.9612616958,
		-0.9563047558,
		-0.9510565161,
		-0.9455185754,
		-0.9396926206,
		-0.9335804263,
		-0.9271838543,
		-0.9205048532,
		-0.9135454574,
		-0.9063077868,
		-0.898794046,
		-0.8910065239,
		-0.8829475925,
		-0.8746197068,
		-0.8660254034,
		-0.8571673003,
		-0.8480480958,
		-0.8386705676,
		-0.8290375722,
		-0.8191520439,
		-0.809016994,
		-0.7986355096,
		-0.7880107532,
		-0.777145961,
		-0.7660444427,
		-0.7547095798,
		-0.743144825,
		-0.7313537011,
		-0.7193397998,
		-0.7071067807,
		-0.6946583699,
		-0.6819983595,
		-0.6691306058,
		-0.6560590284,
		-0.6427876091,
		-0.6293203905,
		-0.6156614747,
		-0.6018150226,
		-0.5877852517,
		-0.5735764357,
		-0.5591929029,
		-0.5446390344,
		-0.5299192636,
		-0.5150380743,
		-0.4999999993,
		-0.4848096196,
		-0.4694715621,
		-0.4539904991,
		-0.4383711461,
		-0.422618261,
		-0.4067366424,
		-0.3907311278,
		-0.3746065927,
		-0.3583679488,
		-0.3420201426,
		-0.3255681537,
		-0.3090169936,
		-0.292371704,
		-0.2756373551,
		-0.2588190443,
		-0.2419218948,
		-0.2249510536,
		-0.20791169,
		-0.1908089946,
		-0.1736481769,
		-0.1564344643,
		-0.1391731002,
		-0.1218693426,
		-0.1045284625,
		-0.08715574194,
		-0.06975647293,
		-0.05233595543,
		-0.03489949589,
		-0.01745240562,
		0.0
};

double sin(double x) {
	MATH;
	if (x < 0.0) {
		x += 3.141592654 * 2.0 * 100.0;
	}
	int i = x * 360.0 / (3.141592654 * 2.0);
	double z = x * 360.0 / (3.141592654 * 2.0);
	z -= i;

	i = i % 360;

	//fprintf(stderr, "z = %f\n", z);

	double a = bad_sine_table[i];
	double b = bad_sine_table[(i+1)%360];

	return a * (1.0-z) + b * (z);
}

double cos(double x) {
	return sin(x + 3.141592654 / 2.0);
}

double atan(double x) {
	return atan2(x,1.0);
}

double hypot(double x, double y) {
	return sqrt(x * x + y * y);
}

double modf(double x, double *iptr) {
	MATH;
	int i = (int)x;
	*iptr = (double)i;
	return x - i;
}

double frexp(double x, int *exp) {
	MATH;
	struct {
		uint32_t lsw;
		uint32_t msw;
	} extract;

	memcpy(&extract, &x, sizeof(double));

	*exp = ((extract.msw & 0x7ff00000) >> 20) - 0x3FE;

	struct {
		uint32_t lsw;
		uint32_t msw;
	} out_double;

	out_double.msw = (extract.msw & 0x800fffff) | 0x3FE00000;
	out_double.lsw = extract.lsw;

	double out;
	memcpy(&out, &out_double, sizeof(double));
	return out;
}

double cosh(double x) {
	return (exp(x) + exp(-x)) / 2.0;
}

double sinh(double x) {
	return (exp(x) - exp(-x)) / 2.0;
}

double tanh(double x) {
	return (exp(2.0*x) - 1.0) / (exp(2.0*x) + 1.0);
}

int fpclassify(double x) {
	union {
		double asFloat;
		uint64_t asInt;
	} bits = {x};
	uint64_t exponent = (bits.asInt >> 52) & 0x7FF;
	uint64_t mantissa = (bits.asInt & 0xFffffFFFFffffULL);

	if (exponent == 0x7FF) {
		return mantissa ? FP_NAN : FP_INFINITE;
	} else if (exponent == 0) {
		return mantissa ? FP_SUBNORMAL : FP_ZERO;
	}
	return FP_NORMAL;
}

double ceil(double x) {
	union {
		double asFloat;
		uint64_t asInt;
	} bits = {x};
	int64_t exponent = ((bits.asInt >> 52) & 0x7FF) - 0x3ff;
	uint64_t mantissa = (bits.asInt & 0xFffffFFFFffffULL);
	if (exponent >= 52 || x == 0) return x;
	if (exponent <= -1) return (bits.asInt >> 63) ? -0.0 : 1.0;
	uint64_t mask = (0xfffffFFFFffffULL >> exponent);
	if (!(mask & mantissa)) return x;
	if (!(bits.asInt >> 63)) {
		bits.asInt += mask;
	}
	bits.asInt &= ~mask;
	return bits.asFloat;
}

double round(double x) {
	union {
		double asFloat;
		uint64_t asInt;
	} bits = {x};
	int64_t exponent = ((bits.asInt >> 52) & 0x7FF) - 0x3ff;
	uint64_t mantissa = (bits.asInt & 0xFffffFFFFffffULL);
	if (exponent >= 52 || x == 0) return x;
	if (exponent < -1) return (bits.asInt >> 63) ? -0.0 : 0.0;
	if (exponent == -1) return x >= 0.5 ? 1.0 : (x <= -0.5 ? -1.0 : ((bits.asInt >> 63) ? -0.0 : 0.0));

	uint64_t mask  = 0xfffffFFFFffffULL >> exponent;
	uint64_t a = mantissa & mask;
	uint64_t b = mantissa & (mask >> 1);

	if (a & ~b) {
		bits.asInt += mask;
		bits.asInt &= ~mask;
		return bits.asFloat;
	}

	bits.asInt &= ~mask;
	return bits.asFloat;
}

float ceilf(float x) {
	return ceil(x);
}

float roundf(float x) {
	return round(x);
}

long lroundf(float x) {
	return round(x);
}

